package com.wyj.task;


import cn.hutool.core.lang.UUID;
import com.wyj.common.LogPortal;
import com.wyj.entity.ActivityConfig;
import com.wyj.entity.HappyRankInfo;
import com.wyj.enums.ActivityType;
import com.wyj.mapper.HappyRankInfoMapper;
import com.wyj.service.AbstractActivityService;
import com.wyj.utils.DateUtil;
import com.wyj.utils.SystemConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
@Lazy(value = false)
public class HappyRankTask extends AbstractActivityService {

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    HappyRankInfoMapper happyRankInfoMapper;

    private final String VALUE_PRE = UUID.fastUUID().toString(true) + "-";

    /**
     * 每3天执行一次
     */
    @Scheduled(cron = "0 0 0 */3 * ?")
    public void run() {
        ActivityConfig actConfig = getActConfig(ActivityType.HAPPY_RANK);
        String activityName = ActivityType.HAPPY_RANK.getName();
        //1.效验活动结束了吗
        BoundValueOperations valueOps = redisTemplate.boundValueOps(SystemConstants.HAPPY_RANK_EXPIRE + activityName);
        if (valueOps == null) {
            return;
        }
        long expire = (long) valueOps.get();
        if (System.currentTimeMillis() <= expire) {
            return;
        }
        // 避免重复
        redisTemplate.delete(SystemConstants.HAPPY_RANK_EXPIRE + activityName);
        //2.获取分布式锁
        boolean tryLock = tryLock(activityName, 10, TimeUnit.SECONDS);
        try {
            if (tryLock) {
                List<HappyRankInfo> happyRankInfos = happyRankInfoMapper.selectList(null);
                String key = SystemConstants.HAPPY_RANK_PRE + actConfig.getStartTime();
                //3.将排行榜数据输入redis当中
                for (HappyRankInfo rankInfo : happyRankInfos) {
                    redisTemplate.boundZSetOps(key).add(rankInfo.getUuid(), rankInfo.getPoints());
                    redisTemplate.expire(key, DateUtil.getDifferDay(actConfig.getStartTime(), actConfig.getEndTime()), TimeUnit.DAYS);
                }
            }
        } catch (Exception e) {
            throw e;
        } finally {
            releaseLockV2(activityName);
        }
    }

    // 获取锁
    public boolean tryLock(String key, long expireTime, TimeUnit unit) {
        long id = Thread.currentThread().getId();
        Boolean aBoolean = redisTemplate.boundValueOps(SystemConstants.HAPPY_RANK_LOCK_KEY + key).setIfAbsent(VALUE_PRE + id, expireTime, unit);
        // 防止 空指针异常
        return Boolean.TRUE.equals(aBoolean);
    }

    // 释放锁
    public void releaseLockV2(String key) {
        // 需要判断下 跟我们上锁的时候是否是同一把锁
        String threadId = VALUE_PRE + Thread.currentThread().getId();
        String id = redisTemplate.boundValueOps(SystemConstants.HAPPY_RANK_LOCK_KEY + key).get().toString();
        if (id.equals(threadId)) {
            redisTemplate.delete(SystemConstants.HAPPY_RANK_LOCK_KEY + key);
        } else {
            LogPortal.error(getClass().getSimpleName() + "删除的锁不是同一个线程的，threadId:{},id:{}", threadId, id);
        }
    }


}
